home *** CD-ROM | disk | FTP | other *** search
- Comment *
- Multi Spooler Ver. 2
- for the IBM PC
- by Rich Winkel
- Columbia, Mo.
-
- For free distribution only
-
- Mspool2 Features
-
- Allows spooling up to 4 printers simultaneously.
- Supports both parallel and serial printers in any
- combination.
- Has a user selectable buffer size up to 63K bytes.
- Sensitive to competing demands for CPU time. Won't
- slow down foreground jobs.
- Allows cancellation of an on-going print operation.
- Can be 'disabled' for use with programs which are
- incompatible with it's operation.
-
-
- Usage:
-
- To install the spooler, at the DOS prompt type:
-
- MSPOOL a b c
- where:
-
- a (= 1 - 4) represents the four possible printers on the PC.
- (1, 2 & 3 correspond to LPT1, LPT2 & LPT3)
-
- b (= 1 - 9) represents the number of 7K chunks of memory to set
- aside for the spooler buffer.
-
- c (= 1 - 4) is an optional parameter used when you wish the
- output to be directed to a serial port.
- (1 and 2 correspond to COM1 and COM2)
-
- Once the spooler is installed, the user need not worry about
- it further; it will begin intercepting all print operations and
- buffering them. However, the operation of the spooler can be
- modified after it has been installed, if the need arises. After
- the spooler has been installed, if you type:
-
- MSPOOL a
-
- where 'a' is the same 'a' you used to install it, you are
- presented with three options: Purge, Disable or Enable. These
- are as follows:
-
- Purge: Drops any characters remaining in the spooler buffer.
- This has the effect of canceling any printing operation
- currently taking place.
-
- Disable: A few programs for the PC operate in a way which
- interferes with MSPOOL's ability to send characters to
- the printer. The result is that MSPOOL captures the
- characters, but doesn't actually begin printing them
- until it's buffer is full or you exit your program.
- 'Disabling' the spooler (prior to running your program)
- keeps the number of characters in it's buffer from
- growing. That is, every time the spooler intercepts a
- character, it prints a character. If it's buffer is
- empty, it's as if it wasn't there at all. It simply
- prints the character it gets when it gets it. If there
- are characters in the buffer at the time the offending
- program is invoked, then when it gets a character to
- print, it fetches the next character in line and prints
- it, and puts the new character at the end of the queue.
-
- Enable: Re-enables spooling.
-
- Hitting any key other than P, D or E has no effect.
-
- Notes:
-
- To spool to a serial printer, first initialize the COM port
- with the MODE command: MODE COMc:baud,parity,databits,stopbits
- etc. DO NOT use the P (continuous retry) option. Then install
- MSPOOL: MSPOOL a b c. This will route all output for LPTa
- through the spooler to the COMc port. DO NOT use the MODE
- redirect command. (i.e. don't use MODE LPT#:=COMn)
-
- To spool to more than one printer, just run the spooler
- repeatedly, specifying each printer in turn.
-
- When spooling to more than one printer, in certain
- circumstances (see tech hype below) the last spooler loaded will
- have priority, then the second to last.
-
- In order for the Purge, Disable, Enable routine to work, you
- should load the spooler(s) last among the 'resident' routine(s)
- which intercept the printer I/O interrupt.
-
- Once the spooler is installed, it's output cannot be re-
- directed to another port, so programs written for this purpose
- (such as QSWAP) will not work.
-
- Technical hype:
-
- This spooler intercepts 2 interrupts: Printer I/O (INT 17H),
- and Keyboard I/O (INT 16H). At installation, it stores the old
- vectors for these interrupts internally and substitutes it's own
- addresses in the interrupt vector table.
- Any call to print is checked as to whether it references the
- spooler's printer. If not, it is passed on to the the old
- printer I/O handler. (could be another spooler, GRAPHICS.COM, the
- ROM routine etc.) If it does reference the spooler's printer,
- the character is put in the spooler's buffer, and the buffer is
- checked to see if it's full. If not, the spooler returns
- to the calling program. Otherwise, the spooler prints the
- next character waiting in the buffer, then returns. If the
- spooler has been 'disabled', it always prints the next character
- in the buffer, regardless of whether the buffer is full.
- Whenever a program makes a keyboard I/O call (INT 16H), the
- spooler checks whether it has a character to print in it's
- buffer. If not, it passes control to the old keyboard I/O
- routine (could be another spooler, the ROM routine etc.).
- Otherwise, it makes one attempt to print a character. It then
- checks to see if the keyboard call will require the keyboard I/O
- routine to wait for a character to be entered from the keyboard
- if no character is already in the keyboard buffer. If not, it
- passes control to the old keyboard I/O handler. Otherwise, it
- looks at the BUFFER_HEAD and BUFFER_TAIL words in the ROM BIOS
- data area to determine if there is a character in the keyboard
- buffer. If there is, it passes control. Otherwise, it begins
- looping, repeatedly attempting to print and checking the keyboard
- buffer until it either runs out of characters or a character is
- entered at the keyboard. It is during this looping process that
- the most recently installed spooler will get the highest
- priority.
- Whenever mspool is run, it checks where the printer I/O
- interrupt vector is pointing to determine whether it has already
- been installed. If it doesn't find a copy of itself there, it
- assumes it is not installed and continues with installation. If
- there is a copy of itself, it checks to see whether the copy is
- configured to intercept calls to the same printer as was
- specified in it's own parameter list (parm 1). If not, it gets
- the segment for the next printer I/O handler up the line from the
- copy and repeats the same procedure until it either lands in
- unfamiliar territory or finds a spooler configured for it's
- printer. If it finds one with the proper configuration, it
- presents you with the 'Purge, Disable, Enable' option.
- Otherwise, it continues with installation.
- During installation, the spooler is patched in accordance
- with the parameters passed to it by DOS, to customize for
- parallel or serial printing, buffer size, LPT number and the
- addresses of the old interrupt routines gotten from the interrupt
- vector table.
- The legal ranges for the printer number and serial port number
- are due to the fact that there is space for 4 ports in both the
- printer and RS-232 tables.
-
- *
-
- PAGE 60,132
- ; MULTI SPOOLER 2 BY RICH WINKEL. FOR FREE DISTRIBUTION ONLY.
- ; CERTAIN AREAS OF CODE ARE MODIFIED BY THE INITIALIZATION ROUTINE TO
- ; CUSTOMIZE FOR THE PRINTER AND BUFFER SIZE WHILE MINIMIZING THE NEED
- ; FOR (SLOW) INDIRECT ADDRESSING. (QUITE A HACK, EH?)
- ; THE MODIFIED CODE AREAS ARE MARKED ON THE RIGHT WITH '*'.
- ;
- CR EQU 0DH ;CARRIAGE RETURN
- ;
- BOTTOM SEGMENT AT 0H
- ORG 058H
- KBDIP DW ? ;INT VECTOR FOR
- KBDCS DW ? ;KEYBOARD I/O
- PRTIP DW ? ;INT VECTOR FOR
- PRTCS DW ? ;PRINTER I/O
- ORG 41AH
- KBHEAD DW ? ;ROM BIOS DATA; POINTERS TO HEAD AND
- KBTAIL DW ? ;TAIL OF KEYBOARD BUFFER
- BOTTOM ENDS
- ;
- MSPOOL SEGMENT
- ASSUME CS:MSPOOL
- ORG 6H
- SEGTOP DW ? ;NUMBER OF BYTES AVAIL IN SEGMENT
- ORG 80H
- UPALEN DB ? ;UNFORMATTED PARM AREA LENGTH
- ;
- ORG 100H
- MAIN PROC NEAR
- JMP INIT ;JUMP TO INITIALIZATION
- HEAD DW OFFSET PRTNUM ;POINTER TO LAST CHAR STORED IN BUFFER
- TAIL DW OFFSET PRTNUM ;POINTER TO LAST CHAR PRINTED
- ;
- ; ROUTINE TO COMPUTE POINTER TO NEXT POSITION IN BUFFER
- INCR: INC BX ;INCREMENT POINTER
- CMP BX,1234H ;ARE WE AT END OF BUFFER? *
- TOP LABEL WORD ;LABEL IS 2 BYTES AFTER CODE TO MODIFY
- JZ L2 ;YES, WRAP AROUND
- RET ;OTHERWISE, GET BACK TO CALLER
- L2: MOV BX,OFFSET PRTNUM;START OF BUFFER
- RET ;GET BACK
- ;
- ; PRINTER I/O INTERRUPT HANDLER
- PRTINT: STI ;INTERRUPTS BACK ON
- CMP DX,12H ;DOES THE CALL REFERENCE OUR PRINTER? *
- LPTN LABEL BYTE ;LABEL IS 1 BYTE AFTER CODE TO MODIFY
- JZ L3 ;YES, HANDLE IT
- ;OTHERWISE, JUMP TO NEXT INT HANDLER
- DB 0EAH ;PREFIX BYTE FOR FAR JUMP
- PJFARIP DW 0H ;IP FOR " " *
- PJFARCS DW 0H ;CS FOR " " *
- L3: OR AH,AH ;PRINT A CHARACTER?
- JNZ BACK ;NO, REPLY PRINTER READY AND RETURN
- PUSH BX ;OTHERWISE RECEIVE CHARACTER
- MOV BX,CS:HEAD ;GET POINTER
- CALL INCR ;INCR TO POINT TO NEXT BUFFER POSITION
- MOV CS:[BX],AL ;STORE CHAR IN BUFFER
- MOV CS:HEAD,BX ;STORE NEW HEAD VALUE
- MOV AX,BX ;FOR SAFE KEEPING
- MOV BX,CS:TAIL ;GET TAIL
- CMP AX,BX ;IS THE BUFFER FULL?
- TOGGLE LABEL BYTE ;AT BYTE TO MODIFY (SPOOLING DISABLE)
- JZ FULL ;YES, SO PRINT A CHARACTER *
- POP BX ;OTHERWISE, RETURN
- BACK: MOV AH,90H ;PRINTER STATUS READY, SELECTED
- IRET ;GET BACK TO CALLER
- FULL: PUSH DX ;PRINT A CHARACTER
- MOV DX,1234H ;POINTER TO STATUS PORT OF PRINTER *
- PRTADD1 LABEL WORD ;LABEL IS 2 BYTES AFTER CODE TO MODIFY
- L5: CALL PRT ;CALL TO PRINT
- CMP BX,CS:TAIL ;HAS A PRINT OCCURRED?
- JZ L5 ;NO, TRY AGAIN
- MOV CS:TAIL,BX ;OTHERWISE, STORE NEW TAIL AND RETURN
- POP DX
- POP BX
- MOV AH,90H ;PRINTER READY, SELECTED
- IRET ;BYE
- ;
- ; KEYBOARD INT HANDLER
- KBDINT: STI ;INTERRUPTS BACK ON
- PUSH BX
- MOV BX,CS:TAIL ;GET POINTER TO LAST CHAR PRINTED
- CMP BX,CS:HEAD ;WAS IT THE LAST CHAR SPOOLED?
- JZ L10 ;YES, JUMP TO NEXT INT HANDLER
- PUSH DX ;OTHERWISE, PRINT A CHARACTER
- PUSH AX
- MOV DX,1234H ;POINTER TO PRINTER STATUS PORT *
- PRTADD2 LABEL WORD ;LABEL IS 2 BYTES AFTER CODE TO MODIFY
- CALL PRT ;CALL TO PRINT
- POP AX
- OR AH,AH ;TEST NATURE OF KBD CALL
- JNZ L9 ;JUMP IF WE ARE NOT TO WAIT FOR KBD INP
- PUSH AX ;OTHERWISE, CHECK IF CHAR IN KBD BUFFER
- PUSH DS
- XOR AX,AX ;POINT DS TO LOW MEMORY
- MOV DS,AX
- ASSUME DS:BOTTOM
- L7: MOV AX,KBHEAD ;IS THERE A CHAR
- CMP AX,KBTAIL ;IN THE KEYBOARD BUFFER?
- JNZ L8 ;YES, JUMP TO NEXT KBD INT HANDLER
- CMP BX,CS:HEAD ;STILL CHARS TO PRINT?
- JZ L8 ;NO, ON TO NEXT KBD INT HANDLER
- CALL PRT ;OTHERWISE, PRINT ANOTHER CHAR
- JMP SHORT L7 ;DO IT AGAIN
- L8: POP DS
- POP AX
- L9: POP DX
- MOV CS:TAIL,BX ;STASH LATEST VALUE OF TAIL
- L10: POP BX
- DB 0EAH ;PREFIX BYTE FOR FAR JUMP
- KJFARIP DW 0H ;IP FOR " " *
- KJFARCS DW 0H ;CS FOR " " *
- ;
- ; ROUTINE TO PRINT A CHARACTER TO RS-232
- PRT: IN AL,DX ;TEST LINE STATUS REG **
- TEST AL,20H ;READY?
- JNZ MSR ;YES, CHECK MODEM STATUS REG
- RET ;OTHERWISE, RETURN
- MSR: INC DX ;POINT TO IT
- IN AL,DX ;GET STATUS
- AND AL,30H ;ISOLATE CTS & DSR
- CMP AL,30H ;BOTH READY?
- JNZ REQUEST ;NO, SIGNAL DTR AND RTS
- SUB DX,06H ;ELSE POINT TO XMIT HOLDING REG
- CALL INCR ;INCREMENT BUFFER POINTER
- MOV AL,CS:[BX] ;GET CHAR
- OUT DX,AL ;OUTPUT
- ADD DX,05H ;POINT BACK TO LSR
- RET ;GET BACK
- REQUEST:SUB DX,02H ;POINT TO MODEM CNTL REG
- MOV AL,03H ;DTR, RTS
- OUT DX,AL ;OUTPUT
- INC DX ;POINT BACK TO LSR
- RET ;GET BACK **
- ;
- ;-------END OF RESIDENT CODE-------
- ;
- ; THE FOLLOWING BYTES ARE USED DURING INITIALIZATION
- ASSUME DS:MSPOOL
- PRTNUM DB 0H ;FIRST PARM PASSED
- BUFFSIZE DB 0H ;SECOND
- COMNUM DB 0H ;THIRD (OPTIONAL)
- ;
- ;-------INITIALIZATION ROUTINE-------
- ;
- ; FIRST PROCESS PARMS
- ;
- INIT: MOV CL,UPALEN ;GET LENGTH OF PARM STRING
- OR CL,CL ;IS IT ZERO?
- JZ OVRLOOP ;JUMP OVER PARM PARSING
- XOR CH,CH ;ZERO FOR LOOPING
- MOV BX,OFFSET UPALEN+1 ;POINT TO PARM AREA
- MOV SI,OFFSET PRTNUM-1 ;POINT TO PLACE TO STASH PARMS
- PROCESS:MOV AL,[BX] ;GET THE PARM
- CMP AL,' ' ;GET RID OF SPACES
- JZ LOOP1
- INC SI ;POINT TO NEXT PARM STORAGE BYTE
- CMP SI,OFFSET COMNUM;PROTECT AGAINST USER ABUSE
- JA NOGOOD ;EXCESSIVE NUMBER OF PARMS GIVEN
- MOV [SI],AL ;FOR SAFE KEEPING
- INC BX ;POINT TO NEXT SPOT IN UPA
- CMP BYTE PTR [BX],' ';WAS THE PARM A SINGLE CHAR?
- JZ LOOP2 ;GOOD
- CMP BYTE PTR [BX],13;CARRIAGE RETURN?
- JZ LOOP2 ;MUST BE AT END OF UPA
- NOGOOD: JMP L25 ;ELSE INVALID PARM
- LOOP1: INC BX ;POINT TO NEXT CHAR IN UPA
- LOOP2: LOOP PROCESS ;BACK FOR MORE
- ;
- ; PROCESS FIRST PARM
- ;
- OVRLOOP:MOV AL,PRTNUM ;GET FIRST PARM
- CMP AL,0H ;NO PARM PASSED?
- JNZ L14
- MOV AL,'1' ;THEN ASSUME '1'
- L14: CMP AL,'1' ;CHECK FOR BOTTOM OF LEGAL RANGE
- JB NOGOOD ;BAD PARM
- CMP AL,'4' ;TOP OF LEGAL RANGE
- JA NOGOOD ;BAD PARM
- SUB AL,'1' ;CONVERT TO CORRESPONDING HEX NUMBER-1
- MOV LPTN-1,AL ;MODIFY CODE
- ;
- ; NOW CHECK IF SPOOLER FOR THIS PRINTER IS ALREADY INSTALLED
- ;
- XOR DX,DX
- MOV ES,DX
- MOV AX,ES:PRTCS ;GET SEGMENT FOR PRT INT FROM TABLE
- CLD ;FORWARD DIRECTION FOR COMPARE
- L19: MOV ES,AX ;GET IN RIGHT SEGMENT
- MOV CX,0010H ;COMPARE 10H BYTES
- MOV SI,OFFSET L3 ;PREPARE TO COMPARE
- MOV DI,SI
- L20: CMPSB ;DOES IT MATCH?
- JNZ CONTINU ;NO, NOT INSTALLED, CONTINUE INSTALLING
- LOOP L20 ;COMPARE NEXT BYTES
- MOV AL,ES:LPTN-1 ;THERE'S A SPOOLER THERE, BUT IS IT
- CMP AL,LPTN-1 ;CONFIGURED FOR OUR PRINTER?
- PATCHON LABEL BYTE ;PTR TO BYTE TO PATCH AT TOGGLE
- JZ L21 ;YES, PURGE, DISABLE OR ENABLE?
- ;NO, CHECK NEXT PRT INT HANDLER UP THE
- ;LINE
- MOV AX,ES:PJFARCS ;GET CS FOR NEXT HANDLER
- PATCHOFF LABEL BYTE ;PTR TO BYTE TO PATCH AT TOGGLE
- JMP SHORT L19 ;CHECK IF IT'S ANOTHER SPOOLER
- L21: MOV AH,09H ;ASK IF WANT TO PURGE, DISABLE OR
- MOV DX,OFFSET MSG4 ;ENABLE INSTALLED SPOOLER
- INT 21H ;DOS CALL
- L22: MOV AH,01H ;GET A CHARACTER FROM THE KEYBOARD
- INT 21H ;DOS CALL
- AND AL,'_' ;FORCE UPPER CASE
- CMP AL,'P' ;CHECK FOR PURGE
- JZ PURGE ;YES, PURGE
- CMP AL,'D' ;CHECK FOR DISABLE
- JZ DISABLE ;SWITCH OFF
- CMP AL,'E' ;CHECK FOR ENABLE
- JZ ENABLE ;SWITCH ON
- INT 20H ;OTHERWISE, BACK TO DOS
- PURGE: MOV AX,ES:HEAD ;GET HEAD FROM OTHER SPOOLER
- MOV ES:TAIL,AX ;PUT IT IN TAIL
- INT 20H ;BACK TO DOS
- DISABLE:MOV AL,PATCHOFF ;TURN IT OFF
- MOV ES:TOGGLE,AL
- INT 20H ;BYE
- ENABLE: MOV AL,PATCHON ;TURN IT ON
- MOV ES:TOGGLE,AL
- INT 20H ;BYE
- ;
- ; SPOOLER IS NOT YET INSTALLED, PROCEED WITH INSTALLATION
- ;
- CONTINU:XOR AH,AH ;FOR FUTURE USE
- MOV AL,COMNUM ;COMM PORT SPECIFIED?
- OR AL,AL
- JZ PARINIT ;NO, INSTALL FOR PARALLEL PRINTER
- CMP AL,'1' ;ELSE CHECK FOR LEGAL RANGE (1-4)
- JB EMSG ;BAD PARM
- CMP AL,'5'
- JB L18 ;GOOD PARM
- EMSG: JMP L25 ;ERROR: INVALID PARM
- L18: SUB AL,'1' ;CONVERT TO CORRESPONDING HEX NUMBER-1
- SHL AL,01H ;FOR WORD OFFSET INTO RS232 TABLE
- MOV BX,05H ;TO ADJUST COM PORT ADDR POINTER
- JMP SHORT GETADDR ;GO GET THE ADDRESS
- PARINIT:MOV AL,LPTN-1 ;RETRIEVE LPT NUMBER
- SHL AL,01H ;MULT BY 2 FOR WORD OFFSET IN PRT TABLE
- ADD AL,08H ;TO POINT TO BASE OF PRINTER TABLE
- MOV BX,01H ;TO ADJUST PARALLEL PORT ADDR POINTER
- MOV CX,DS ;NOW OVERLAY SERIAL PRINT ROUTINE WITH
- MOV ES,CX ;PARALLEL PRINT ROUTINE
- MOV SI,OFFSET PARAPTCH;POINT TO PATCH FOR PARALLEL PRINTER
- MOV DI,OFFSET PRT ;POINT TO SERIAL PRINT ROUTINE
- MOV CX,PPLEN ;LENGTH OF PARAPTCH
- ;DIRECTION FLAG IS ALREADY CLEAR
- REP MOVSB ;MAKE PATCH
- GETADDR:ADD AX,400H ;POINT TO PROPER TABLE (RS232 OR PARAL)
- MOV SI,AX ;PREPARE TO GET ENTRY IN TABLE
- MOV ES,DX ;GET IN RIGHT SEGMENT
- MOV AX,ES:[SI] ;GET ENTRY FROM TABLE
- OR AX,AX ;IS ANYTHING THERE?
- JNZ DEVOK ;YES, CONTINUE
- JMP L26 ;ERROR: DEVICE NONEXISTENT
- DEVOK: ADD AX,BX ;POINT TO PROPER STATUS PORT OF DEVICE
- MOV PRTADD1-2,AX ;PATCH CODE
- MOV PRTADD2-2,AX ;DITTO
- ;
- ; PROCESS BUFFER SIZE PARAMETER
- ;
- MOV AL,BUFFSIZE ;GET BUFFER SIZE PARAMETER
- CMP AL,'1' ;CHECK FOR BOTTOM OF LEGAL RANGE
- JB L25 ;ERROR IF BELOW
- CMP AL,'9' ;CHECK FOR TOP OF LEGAL RANGE
- JA L25 ;ERROR IF ABOVE
- SUB AL,'0' ;CONVERT TO CORRESPONDING HEX NUMBER
- XOR AH,AH
- MOV CX,1C00H ;MULTIPLY BY
- MUL CX ;7K TO GET BUFFER SIZE
- ADD AX,OFFSET PRTNUM;ADD RESIDENT CODE SIZE TO GET TOTAL
- CMP AX,SEGTOP ;IS THERE ROOM?
- JA L27 ;NO, ERROR
- MOV TOP-2,AX ;MODIFY CODE
- ;
- ; NOW THE FINAL INSTALLATION
- ;
- MOV ES,DX ;GET VECTORS FROM THE INT TABLE AT SEG 0
- MOV AX,ES:PRTIP ;IP FOR INT 17H
- MOV PJFARIP,AX ;MODIFY CODE
- MOV AX,ES:PRTCS ;CS FOR INT 17H
- MOV PJFARCS,AX ;MODIFY CODE
- MOV AX,ES:KBDIP ;IP FOR INT 16H
- MOV KJFARIP,AX ;MODIFY CODE
- MOV AX,ES:KBDCS ;CS FOR INT 16H
- MOV KJFARCS,AX ;MODIFY CODE
- MOV AX,2517H ;USE DOS TO POINT INT 17H TO US
- MOV DX,OFFSET PRTINT;ADDR OF PRINT INT HANDLER
- INT 21H ;ADJUST INTERRUPT
- MOV AX,2516H ;USE DOS TO POINT INT 16H TO US
- MOV DX,OFFSET KBDINT;ADDR OF KBD INT HANDLER
- INT 21H ;DO IT
- MOV AH,09H ;MESSAGE TO USER:
- MOV DX,OFFSET MSG5 ;'SPOOLER INSTALLED'
- INT 21H ;DO IT
- MOV DX,TOP-2 ;GET TOTAL SIZE OF SPOOLER
- INT 27H ;TERMINATE AND STAY RESIDENT
- ;
- ; ERROR MESSAGES
- ;
- L25: MOV AH,09H ;MESSAGE: 'BAD PARMS'
- MOV DX,OFFSET MSG1
- INT 21H
- INT 20H ;ADIOS
- L26: MOV AH,09H ;MESSAGE: 'NO PORT!
- MOV DX,OFFSET MSG2
- INT 21H
- INT 20H ;ADIOS
- L27: MOV AH,09H ;MESSAGE: 'NOT ENUF ROOM!'
- MOV DX,OFFSET MSG3
- INT 21H
- INT 20H ;ADIOS
- ;
- MSG1 DB 'Error: Invalid parameter(s).',0DH,0AH
- DB 'Parm 1 represents the printer and must be >0 and <5.',0DH,0AH
- DB 'Parm 2 is the size of the buffer in 7K blocks and must be '
- DB '>0 and <10.',0DH,0AH
- DB 'Parm 3 is the optional COM port to re-direct to, and must '
- DB 'be >0 and <5.$'
- MSG2 DB 'Error: Output port non-existent!$'
- MSG3 DB 'Error: Not enough memory for requested buffer.$'
- MSG4 DB 'Mspool2 already installed. Purge, Disable, Enable? (P/D/E): $'
- MSG5 DB 0DH,0AH,09H,'Multi Spooler2 by Rich Winkel',0DH,0AH,0AH
- DB 09H,'>> Multi Spooler installed <<',0DH,0AH,'$'
- ;
- ;
- ;PATCH TO PRINT TO PARALLEL PRINTER (OVERLAYS PRT)
- ;
- PARAPTCH LABEL BYTE
- IN AL,DX ;GET PRINTER STATUS
- TEST AL,80H ;READY?
- JZ L99 ;NO, GET BACK
- ; THE FOLLOWING 3 BYTES ARE A CALL TO THE INCR ROUTINE.
- ; HOWEVER, THE OFFSET WORD FOR THE CALL HAD TO BE ADJUSTED
- ; FOR THE ACTUAL LOCATION OF THIS ROUTINE WHEN IT IS
- ; USED, SINCE IT WOULD BE PATCHED OVER THE ROUTINE 'PRT'.
- DB 0E8H ;PREFIX BYTE FOR INTRASEGMENT CALL
- DW SETOFF + OFFSET PARAPTCH - JNK
- JNK EQU $
- MOV AL,CS:[BX] ;GET CHAR
- DEC DX ;POINT TO CHAR OUT PORT
- OUT DX,AL ;GET IT GONE
- INC DX ;POINT TO
- INC DX ;STROBE PORT
- MOV AL,1DH ;ZAP IT
- OUT DX,AL
- MOV AL,1CH ;STROBE OFF
- OUT DX,AL
- DEC DX ;POINT BACK TO STATUS PORT
- L99: RET ;GET BACK
- PPLEN EQU $-OFFSET PARAPTCH ;LENGTH OF PATCH ABOVE
- SETOFF EQU OFFSET INCR - OFFSET PRT ;TO USE TO ADJUST CALL IN
- ;PATCH FOR PARA PRINTER
- MAIN ENDP
- MSPOOL ENDS
- END MAIN